!> author: 左志华
!> date: 2022-07-20
!>
!> Save pif.sph <br>
!> 保存为 pif.sph
!> @note 使用 H5fortran 库, HDF5 >= 1.10.6
module sph_save_h5part

    use h5part_m
    use sph_kinds, only: rk
    use seakeeping_time, only: timer
    use seakeeping_filesystem, only: is_exist, operator(.join.)
    use sph_region_type, only: region_t
    use sph_terminal, only: green

contains

    !> Save pif.h5part <br>
    !> 保存为 pif.h5part (核心: HDF5 格式)
    !> @note H5part 中, 每个时间步内有数据集: 坐标 x-y-z, 速度 Vx-Vy, 质量 Mass, 密度 Density, 压强 P, 内能 U, 粒子类型 Itype
    impure subroutine save_h5part(file, nml, region, skip)
        character(*), intent(in) :: file        !! file name <br>
                                                !! 路径名
        character(*), intent(in) :: nml         !! Namelist 文件名
        type(region_t), intent(in) :: region    !! Region <br>
                                                !! 计算域
        logical, intent(in) :: skip             !! Skip <br>
                                                !! 跳过
        integer(8) :: fid, status
        logical :: cover; integer :: i, stat
        real(rk), allocatable :: z(:, :)
        type(timer) :: time

        if (is_exist(file) .and. .not. skip) then
            write (*, '(a)', advance='no') green('The file already exists, will the original file be overwritten? (t/f): ')
            read (*, *, iostat=stat) cover
            if (.not. cover .or. stat /= 0) return
        end if

        fid = h5pt_openw(file)
        if (fid < 0) then
            error stop "file in use: "//file
        end if

        ! ---------------------- 属性 ---------------------- !
        call save_pif_attr(nml, "starter", time%nowtime(), rk, [region%nreal, region%nvirt, 0, region%ntotal, 0], &
                           region%dim, region%hsml)

        allocate (z(region%ntotal, region%dim), source=0.0_rk)
        ! ------------------ 初始时间步数据 ----------------- !
        status = h5pt_setnpoints(fid, int(region%ntotal, 8))
        status = h5pt_setstep(fid, 1_8)
        status = h5pt_writestepattrib_r8(fid, "RealTime", [0.0_8], 1_8)

        status = h5pt_writedata_r8(fid, "z", z(:, 1))  ! paraview 需要 z 变量

        ! @note 值复制输出，可能会存在性能问题，这是因为 h5part 以向量存储数据，方便可视化；Ti-SPH 以矩阵存储数据，
        ! 方便高效运算；因此需要将矩阵转换为向量。
        do concurrent(i=1:region%ntotal)
            z(i, :) = region%loc(:, i)
        end do
        status = h5pt_writedata_r8(fid, "x", z(:, 1))
        status = h5pt_writedata_r8(fid, "y", z(:, 2))

        do concurrent(i=1:region%ntotal)
            z(i, :) = region%vel(:, i)
        end do
        status = h5pt_writedata_r8(fid, "Vx", z(:, 1))
        status = h5pt_writedata_r8(fid, "Vy", z(:, 2))

        status = h5pt_writedata_r8(fid, "Mass", region%mass)
        status = h5pt_writedata_r8(fid, "Density", region%rho)
        status = h5pt_writedata_r8(fid, "P", region%p)
        status = h5pt_writedata_r8(fid, "U", region%u)
        status = h5pt_writedata_i4(fid, "Itype", region%itype)
        status = h5pt_close(fid)

    end subroutine save_h5part

    !> Save attributes to namelist <br>
    !> 保存属性到 namelist: pif.nml
    subroutine save_pif_attr(file, creator, create_date, real_kind, nums, dim, hsml)
        character(*), intent(in) :: file        !! Namelist 文件名
        character(*), intent(in) :: creator, create_date
        integer, intent(in) :: real_kind, nums(5), dim
        real(rk), intent(in) :: hsml
        namelist /pif_attr/ creator, create_date, real_kind, nums, dim, hsml
        integer :: iunit

        open (newunit=iunit, file=file)
        write (iunit, nml=pif_attr)
        close (iunit)

    end subroutine save_pif_attr

end module sph_save_h5part
